{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "celltoolbar": "Tags",
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.5"
    },
    "colab": {
      "name": "Part 06 - Federated Learning on MNIST using a CNN.ipynb",
      "provenance": [],
      "collapsed_sections": []
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "metadata": {
        "tags": [
          "parameters"
        ],
        "id": "js2dVnY7kps8",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "epochs = 10"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wmWBx956kptG",
        "colab_type": "text"
      },
      "source": [
        "# পার্ট 6 - CNN ব্যবহার করে MNIST এর উপরে ফেডারেটেড লার্নিং\n",
        "\n",
        "## PyTorch + PySyft এর ১০ টি লাইন দিয়ে ফেডারেটেড লার্নিংয়ে আপগ্রেড করুন\n",
        "\n",
        "\n",
        "### প্রসঙ্গ\n",
        "\n",
        "ফেডারেটেড লার্নিং একটি অত্যন্ত উত্তেজনাপূর্ণ এবং উৎসাহব্যঞ্জক মেশিন লার্নিং কৌশল যা এমন সিস্টেম তৈরিতে লক্ষ্য করে যা কি-না বিকেন্দ্রীভূত ডেটা থেকে শিখতে পারে। ধারণাটি হলো ডেটাটি তার প্রযোজকের হাতে রয়েছে (যা - কর্মী_নামেও পরিচিত), যা গোপনীয়তা এবং মালিকানা উন্নত করতে সহায়তা করে এবং মডেলটি শ্রমিকদের মধ্যে ভাগ করে নেওয়া হয়েছে। একটি তাৎক্ষণিক অ্যাপ্লিকেশন হলো - টেক্সট লেখার সময় আপনার মোবাইল ফোনে পরবর্তী শব্দটির পূর্বাভাস দেওয়া। সেক্ষেত্রে আপনি চান না আপনার ডাটা প্রশিক্ষণের জন্য ব্যবহৃত হোক। যেমনঃ আপনার বার্তা - কোনও কেন্দ্রীয় সার্ভারে প্রেরণ করা হোক।\n",
        "\n",
        "ফেডারেটড লার্নিংয়ের উত্থান তথ্যের সাথে গোপনীয়তা সচেতনতার প্রসারের সাথে দৃঢ়ভাবে সংযুক্ত এবং ইইউতে জিডিপিআর যা মে, ২০১৮  সাল থেকে ডেটা সুরক্ষা জারি করে, সেটি অনুঘটক হিসাবে কাজ করেছে। নিয়ন্ত্রণের পূর্বাভাস দেওয়ার জন্য, অ্যাপল বা গুগলের মতো বড় বড় প্রতিষ্ঠান বিশেষত মোবাইল ব্যবহারকারীর গোপনীয়তা রক্ষার জন্য এই প্রযুক্তিতে ব্যাপক বিনিয়োগ শুরু করেছে, তবে তারা তাদের সরঞ্জামগুলি উন্মুক্ত করেনি। OpenMined-এ আমরা বিশ্বাস করি যে যে কেউ মেশিন লার্নিং প্রকল্প পরিচালনা করতে ইচ্ছুক তিনি খুব অল্প প্রচেষ্টা সহ গোপনীয়তা সংরক্ষণের সরঞ্জামগুলি প্রয়োগ করতে সক্ষম হবেন। আমরা এক লাইনে ডেটা এনক্রিপ্ট করার জন্য সরঞ্জাম তৈরি করেছি [আমাদের ব্লগ পোস্টে উল্লিখিত](https://blog.openmined.org/training-cnns-using-spdz/) এবং আমরা এখন নতুন পাইটর্চ 1.0 সংস্করণ ব্যবহার করে আমাদের ফেডারেটেড লার্নিং ফ্রেমওয়ার্ক প্রকাশ করি যা উৎসাহ অর্জন করে সুরক্ষিত এবং স্কেলযোগ্য মডেলগুলি তৈরিতে একটি intuitive ইন্টারফেস সরবরাহ করতে।\n",
        "\n",
        "এই টিউটোরিয়ালে, আমরা সরাসরি ব্যবহার করব [পাইটর্চ ব্যবহার করে MNIST-তে CNN প্রশিক্ষণের প্রথাগত উদাহরণ](https://github.com/pytorch/example/blob/master/mnist/main.py) এবং দেখাবো আমাদের [PySyft লাইব্রেরি](https://github.com/OpenMined/PySyft/) ব্যবহার করে এর সাথে ফেডারেটেড লার্নিং বাস্তবায়ন করা কতটা সহজ। আমরা উদাহরণের প্রতিটি অংশে যাবো এবং সেই কোডটি আন্ডারলাইন করব যা পরিবর্তিত হয়েছে।\n",
        "\n",
        "আপনি এই উপাদানগুলি [আমাদের ব্লগপোস্ট](https://blog.openmined.org/upgrade-to-fedrated-learning-in-10-lines) এও পেতে পারেন।\n",
        "\n",
        "লেখক:\n",
        "- থিও রাইফেল(Théo Ryffel) - গিটহাব: [@LaRiffle](https://github.com/LaRiffle)\n",
        "\n",
        "অনুবাদক:\n",
        "- সায়ন্তন দাস - গিটহাব: [@ucalyptus](https://github.com/ucalyptus)\n",
        "\n",
        "- মীর মোহাম্মদ জাবের(Mir Mohammad Jaber) - Twitter: [@jabertuhin](https://twitter.com/jabertuhin)\n",
        "\n",
        "**ঠিক আছে, শুরু করা যাক!**"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EcyS9Z5NkptH",
        "colab_type": "text"
      },
      "source": [
        "### ইম্পোর্ট এবং মডেল নির্দিষ্টকরণ\n",
        "\n",
        "প্রথমে আমরা অফিসিয়াল প্যাকেজসমূহ ইম্পোর্ট করি"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "L7STRtRBkptI",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.nn.functional as F\n",
        "import torch.optim as optim\n",
        "from torchvision import datasets, transforms"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MM8gf315kptS",
        "colab_type": "text"
      },
      "source": [
        "এবং এরপর পাইসাইফ্ট সম্পর্কিত নির্দিষ্টগুলো প্যাকেজগুলো। বিশেষত আমরা দূরবর্তী কর্মী `alice` এবং `bob`-কে সংজ্ঞায়িত করি"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Zql5FLS4kptW",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import syft as sy  # <-- NEW: import the Pysyft library\n",
        "hook = sy.TorchHook(torch)  # <-- NEW: hook PyTorch ie add extra functionalities to support Federated Learning\n",
        "bob = sy.VirtualWorker(hook, id=\"bob\")  # <-- NEW: define remote worker bob\n",
        "alice = sy.VirtualWorker(hook, id=\"alice\")  # <-- NEW: and alice"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZlxKwKutkptf",
        "colab_type": "text"
      },
      "source": [
        "আমরা শেখার কাজটির সেটিংস(settings) সংজ্ঞায়িত করি"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "KBs4KsvUkptg",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class Arguments():\n",
        "    def __init__(self):\n",
        "        self.batch_size = 64\n",
        "        self.test_batch_size = 1000\n",
        "        self.epochs = epochs\n",
        "        self.lr = 0.01\n",
        "        self.momentum = 0.5\n",
        "        self.no_cuda = False\n",
        "        self.seed = 1\n",
        "        self.log_interval = 30\n",
        "        self.save_model = False\n",
        "\n",
        "args = Arguments()\n",
        "\n",
        "use_cuda = not args.no_cuda and torch.cuda.is_available()\n",
        "\n",
        "torch.manual_seed(args.seed)\n",
        "\n",
        "device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n",
        "\n",
        "kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sfHJDve0kptn",
        "colab_type": "text"
      },
      "source": [
        "### ডেটা লোড করা এবং কর্মীদের কাছে প্রেরণ\n",
        "আমরা প্রথমে ডেটা লোড করি এবং প্রশিক্ষণ ডেটাসেটকে। `ফেডারেট` পদ্ধতিটি ব্যবহার করে কর্মীদের জুড়ে ফেডারেশনযুক্ত ডেটাসেট বিভক্তিতে রূপান্তর করি। এই ফেডারেটেড ডেটাসেটটি এখন একটি ফেডারেটেড ডেটা লোডারকে দেওয়া হয়। টেস্ট ডেটাসেট অপরিবর্তিত রয়েছে।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Md4g0GCUkptp",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "federated_train_loader = sy.FederatedDataLoader( # <-- this is now a FederatedDataLoader \n",
        "    datasets.MNIST('../data', train=True, download=True,\n",
        "                   transform=transforms.Compose([\n",
        "                       transforms.ToTensor(),\n",
        "                       transforms.Normalize((0.1307,), (0.3081,))\n",
        "                   ]))\n",
        "    .federate((bob, alice)), # <-- NEW: we distribute the dataset across all the workers, it's now a FederatedDataset\n",
        "    batch_size=args.batch_size, shuffle=True, **kwargs)\n",
        "\n",
        "test_loader = torch.utils.data.DataLoader(\n",
        "    datasets.MNIST('../data', train=False, transform=transforms.Compose([\n",
        "                       transforms.ToTensor(),\n",
        "                       transforms.Normalize((0.1307,), (0.3081,))\n",
        "                   ])),\n",
        "    batch_size=args.test_batch_size, shuffle=True, **kwargs)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m_MAjSuPkptu",
        "colab_type": "text"
      },
      "source": [
        "### CNN স্পেসিফিকেশন\n",
        "এখানে আমরা অফিসিয়াল উদাহরণের ঠিক একই সিএনএন ব্যবহার করি।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "JZkpLMy-kptv",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class Net(nn.Module):\n",
        "    def __init__(self):\n",
        "        super(Net, self).__init__()\n",
        "        self.conv1 = nn.Conv2d(1, 20, 5, 1)\n",
        "        self.conv2 = nn.Conv2d(20, 50, 5, 1)\n",
        "        self.fc1 = nn.Linear(4*4*50, 500)\n",
        "        self.fc2 = nn.Linear(500, 10)\n",
        "\n",
        "    def forward(self, x):\n",
        "        x = F.relu(self.conv1(x))\n",
        "        x = F.max_pool2d(x, 2, 2)\n",
        "        x = F.relu(self.conv2(x))\n",
        "        x = F.max_pool2d(x, 2, 2)\n",
        "        x = x.view(-1, 4*4*50)\n",
        "        x = F.relu(self.fc1(x))\n",
        "        x = self.fc2(x)\n",
        "        return F.log_softmax(x, dim=1)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yukgldqkkptz",
        "colab_type": "text"
      },
      "source": [
        "### ট্রেন এবং টেস্টের ফাংশনগুলো সংজ্ঞায়িত করুন\n",
        "ট্রেনের ফাংশনগুলোর জন্য, ডেটা ব্যাচগুলি `alice` এবং `bob` জুড়ে বিতরণ করা হয়েছে, তাই আপনাকে প্রতিটি ব্যাচের জন্য সঠিক জায়গায় মডেলটি প্রেরণ করতে হবে। তারপরে, আপনি স্থানীয় পাইটর্চ যেভাবে ব্যবহার করছেন তেমন একই সিনট্যাক্সের সাহায্যে আপনি সমস্ত ক্রিয়াকলাপ দূরবর্তীভাবে সম্পাদন করেন। আপনার কাজ শেষ হয়ে গেলে, আপনি আপডেট হওয়া মডেলটি এবং এর লস(loss) ফিরে পেয়েছেন এতে আরো উন্নতি খোঁজার জন্য।"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-u1PiI9Dkpt1",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def train(args, model, device, federated_train_loader, optimizer, epoch):\n",
        "    model.train()\n",
        "    for batch_idx, (data, target) in enumerate(federated_train_loader): # <-- now it is a distributed dataset\n",
        "        model.send(data.location) # <-- NEW: send the model to the right location\n",
        "        data, target = data.to(device), target.to(device)\n",
        "        optimizer.zero_grad()\n",
        "        output = model(data)\n",
        "        loss = F.nll_loss(output, target)\n",
        "        loss.backward()\n",
        "        optimizer.step()\n",
        "        model.get() # <-- NEW: get the model back\n",
        "        if batch_idx % args.log_interval == 0:\n",
        "            loss = loss.get() # <-- NEW: get the loss back\n",
        "            print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n",
        "                epoch, batch_idx * args.batch_size, len(federated_train_loader) * args.batch_size,\n",
        "                100. * batch_idx / len(federated_train_loader), loss.item()))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9XAJVhhykpt6",
        "colab_type": "text"
      },
      "source": [
        "টেস্ট ফাংশনগুলো বদলায় না!"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "hYbzfnwTkpt8",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def test(args, model, device, test_loader):\n",
        "    model.eval()\n",
        "    test_loss = 0\n",
        "    correct = 0\n",
        "    with torch.no_grad():\n",
        "        for data, target in test_loader:\n",
        "            data, target = data.to(device), target.to(device)\n",
        "            output = model(data)\n",
        "            test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss\n",
        "            pred = output.argmax(1, keepdim=True) # get the index of the max log-probability \n",
        "            correct += pred.eq(target.view_as(pred)).sum().item()\n",
        "\n",
        "    test_loss /= len(test_loader.dataset)\n",
        "\n",
        "    print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
        "        test_loss, correct, len(test_loader.dataset),\n",
        "        100. * correct / len(test_loader.dataset)))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rOBazTR1kpuA",
        "colab_type": "text"
      },
      "source": [
        "### প্রশিক্ষণ চালু করুন!"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "CLxFTK8wkpuC",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "%%time\n",
        "model = Net().to(device)\n",
        "optimizer = optim.SGD(model.parameters(), lr=args.lr) # TODO momentum is not supported at the moment\n",
        "\n",
        "for epoch in range(1, args.epochs + 1):\n",
        "    train(args, model, device, federated_train_loader, optimizer, epoch)\n",
        "    test(args, model, device, test_loader)\n",
        "\n",
        "if (args.save_model):\n",
        "    torch.save(model.state_dict(), \"mnist_cnn.pt\")\n",
        "\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YhdbvOhGkpuJ",
        "colab_type": "text"
      },
      "source": [
        "এ voilà! আপনি এখানে ফেডারেটেড লার্নিং ব্যবহার করে দূরবর্তী ডেটাতে একটি মডেল প্রশিক্ষণ দিয়েছেন!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cOJ20SIxkpuK",
        "colab_type": "text"
      },
      "source": [
        "## শেষ একটি  জিনিস\n",
        "আমি জানি যে আপনি জিজ্ঞাসা করতে মারা যাচ্ছেন এমন একটি প্রশ্ন রয়েছে: **সাধারণ পাইটর্চের তুলনায় ফেডারেট লার্নিং করতে কত সময় লাগে?**\n",
        "\n",
        "গণনার সময়টি আসলে **স্বাভাবিক পাইটর্চ সম্পাদনের জন্য ব্যবহৃত** বারের চেয়ে দ্বিগুণ কম! আরও স্পষ্টভাবে, এটি 1.9 গুণ বেশি সময় নেয়, যা আমরা যুক্ত করতে সক্ষম হওয়া বৈশিষ্ট্যের তুলনায় খুব কম।"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cSsTCJE9kpuL",
        "colab_type": "text"
      },
      "source": [
        "## উপসংহার\n",
        "\n",
        "যেমন আপনি পর্যবেক্ষণ করেন, আমরা MNIST অফিসিয়াল পাইটর্চ উদাহরণটিকে বাস্তব ফেডারেট লার্নিং সেটিংয়ে আপগ্রেড করার জন্য ১০ টি লাইন কোড সংশোধন করেছি!\n",
        "\n",
        "অবশ্যই, আমরা এমন অনেক উন্নতির কথা ভাবতে পারি। আমরা চাই শ্রমিকদের মধ্যে সমান্তরালভাবে গণনা পরিচালিত করতে এবং ফেডারেটেড গড় সম্পাদন করতে, কেন্দ্রীয় মডেলকে প্রতি `n` ব্যাচ পরপর আপডেট করতে, শ্রমিকদের মধ্যে যোগাযোগের জন্য আমরা যে বার্তাগুলি ব্যবহার করি তা হ্রাস করতে এবং আরো কিছু। আমরা এইসব ফিচারের উপরে কাজ করছি ফেডরেটেড লার্নিংকে উৎপাদন পরিবেশের জন্য প্রস্তুত করার জন্য এবং সেগুলো রিলিজ হওয়ার সাথে সাথে আমরা সেগুলো নিয়ে লিখবো।\n",
        "\n",
        "আপনার এখন ফেডারেটেড লার্নিং নিজেই করতে সক্ষম হওয়া উচিত! আপনি যদি এটি উপভোগ করেন এবং গোপনীয়তা সংরক্ষণ, এআই এবং এআই সরবরাহ চেইনের (ডেটা) বিকেন্দ্রীভূত মালিকানার দিকে আন্দোলনে যোগ দিতে চান, আপনি নিম্নলিখিত উপায়ে এটি করতে পারেন!\n",
        "\n",
        "### PySyft -কে গিটহাবে স্টার দিন\n",
        "\n",
        "আমাদের কমিউনিটিকে সাহায্য করার সবচেয়ে সহজ পন্থা হলো রিপোজিটোরিতে স্টার দেয়া! এটি আমরা যে দারুন সরঞ্জাম তৈরি করছি সে ব্যাপারে সচেতনতা বৃদ্ধি করতে সাহায্য করে।\n",
        "\n",
        "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
        "\n",
        "### গিটহাব থেকে আমাদের টিউটোরিয়ালগুলি বাছাই করুন!\n",
        "\n",
        "ফেডারেটেড এবং প্রাইভেসি-প্রিজারভেভিং লার্নিংয়ের চেহারা কেমন হওয়া উচিত এবং আমরা এটির জন্য ইটগুলি কীভাবে তৈরি করছি সে সম্পর্কে আরও ভাল ধারণা পেতে আমরা সত্যিই দুর্দান্ত টিউটোরিয়াল তৈরি করেছি।\n",
        "\n",
        "- [পাইসাইফ্ট টিউটোরিয়াল চেকআউট করুন](https://github.com/OpenMined/PySyft/tree/master/example/tutorials)\n",
        "\n",
        "\n",
        "### আমাদের স্ল্যাকে(Slack) যোগ দিন!\n",
        "\n",
        "সর্বশেষতম অগ্রগতিতে আপ টু ডেট রাখার সর্বোত্তম উপায় হলো আমাদের সম্প্রদায়ে যোগদান করা!\n",
        "\n",
        "- [Join slack.openmined.org](http://slack.openmined.org)\n",
        "\n",
        "### একটি কোড প্রকল্পে যোগদান করুন!\n",
        "\n",
        "আমাদের কমিউনিটিতে অবদান রাখার সেরা উপায় হলো একজন কোড অবদানকারীতে পরিণত হওয়া। যেকোন সময় আপনি PySyft এর গিটহাব ইস্যুর পেজে যেতে পারেন এবং \"Projects\" দিয়ে বাছাই করবেন। এর মাধ্যমে আপনি যে সকল প্রজেক্টে যোগদান করতে পারবেন সেগুলোর উপরের দিকের টিকেটের ওভারভিউ পাবেন। আপনি যদি কোন প্রজেক্টে জয়েন করতে ইচ্ছুক না হোন, কিন্তু কিছুটা কোডিং করতে ইচ্ছুক সেক্ষেত্রে আপনি \"one off\" মিনি প্রজেক্টগুলো দেখতে পারেন গিটহাব ইস্যুতে \"good first issue\" চিহ্নিত ইস্যুগুলো।\n",
        "\n",
        "- [good first issue](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
        "\n",
        "### দান করুন\n",
        "\n",
        "আপনার যদি আমাদের কোডবেজে অবদান রাখারা সময় না হয়, কিন্তু এরপরও আমাদেরকে সমর্থন দিতে চান তাহলে আমাদের উন্মুক্ত সংগ্রহের সমর্থক হতে পারেন। সকল ধরনের দানের অর্থ আমাদের ওয়েব হোস্টিং এবং অন্যান্য কমিউনিটি কার্যক্রমে খরচ হয় যেমন - হ্যাকাথন, মিটাপ।\n",
        "\n",
        "- [OpenMined's Open Collective Page](https://opencollective.com/openmined)"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "pA4W3CiAkpuN",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}